// This is the main DLL file.

#include "stdafx.h"

#include "HidDevices.h"

using namespace HidLib;
using namespace System::Collections::Generic;
using namespace System::Text;
using namespace System::Runtime::InteropServices;

array<HidDevice^>^ HidDevices::Enumerate(String^ DevicePath)
{
	return Enumerate(gcnew HidDeviceIdentifier(DevicePath));
}

array<HidDevice^>^ HidDevices::Enumerate(int VendorId, int ProductId)
{
	return Enumerate(gcnew HidDeviceIdentifier(VendorId, ProductId));
}

array<HidDevice^>^ HidDevices::Enumerate(HidDeviceIdentifier^ Identifier)
{
	List<HidDevice^>^ Devices = gcnew List<HidDevice^>();
	GUID ClassGuid;
	HANDLE hDevInfo;
	SP_DEVINFO_DATA DevInfoData;
	SP_DEVICE_INTERFACE_DATA DevInterfaceData;
	DWORD DeviceIndex = 0;
	DWORD InterfaceIndex = 0;
	DWORD Length = 0;
	DWORD Required = 0;
	DWORD RegType = 0;
	PSP_DEVICE_INTERFACE_DETAIL_DATA DetailData;

	HidD_GetHidGuid(&ClassGuid);

	hDevInfo = SetupDiGetClassDevs(&ClassGuid, NULL, NULL, DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);

	DevInfoData.cbSize = sizeof(DevInfoData);

	while(SetupDiEnumDeviceInfo(hDevInfo, DeviceIndex, &DevInfoData) == TRUE)
	{
		DevInterfaceData.cbSize = sizeof(DevInterfaceData);
		DeviceIndex++;
		InterfaceIndex = 0;
		while(SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &ClassGuid, InterfaceIndex, &DevInterfaceData) == TRUE)
		{
			InterfaceIndex++;
			PBYTE Buffer = new BYTE[255];
			DWORD Required;
			String^ Description;
			String^ DevicePath;

			SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevInterfaceData, NULL, 0, &Length, NULL);

			DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(Length);
			DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);

			SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevInterfaceData, DetailData, Length, &Required, NULL);

			Required = 0;

			if(SetupDiGetDeviceRegistryProperty(hDevInfo, &DevInfoData, SPDRP_DEVICEDESC, &RegType, Buffer, 255, &Required) == TRUE)
			{
				Description = Marshal::PtrToStringUni((IntPtr)Buffer, Required);
			}

			free(Buffer);

			DevicePath = Marshal::PtrToStringUni((IntPtr)DetailData->DevicePath,wcslen(DetailData->DevicePath));

			HidDevice^ Device = gcnew HidDevice(DevicePath,Description);

			if (Identifier->Type == HidDeviceIdentifier::IdentifierTypes::Any ||
				(Identifier->Type == HidDeviceIdentifier::IdentifierTypes::DevicePath && Identifier->DevicePath->Equals(DevicePath)) ||
				(Identifier->Type == HidDeviceIdentifier::IdentifierTypes::VendorId && Identifier->VendorId.Equals(Device->Attributes->VendorId)) ||
				(Identifier->Type == HidDeviceIdentifier::IdentifierTypes::VendorAndProductId && Identifier->VendorId.Equals(Device->Attributes->VendorId) &&
				Identifier->ProductId.Equals(Device->Attributes->ProductId)))
			{
				Devices->Add(Device);
			}
		}
	}

	SetupDiDestroyDeviceInfoList(hDevInfo);

	return Devices->ToArray();
}

bool HidDevices::IsConnected(String^ DevicePath)
{
	array<HidDevice^>^ Devices = Enumerate(DevicePath);
	return Devices->Length > 0;
}